package com.fanxuankai.boot.jenkins.component;

import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.fanxuankai.boot.jenkins.autoconfigure.JenkinsProperties;
import com.fanxuankai.boot.jenkins.autoconfigure.JenkinsSyncProperties;
import com.offbytwo.jenkins.JenkinsServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author fanxuankai
 */
public class JenkinsItemSynchronizer implements ApplicationRunner {
    private final JenkinsServer jenkinsServer;
    private final JenkinsSyncProperties syncProperties;
    private final TemplateEngine templateEngine;
    private static final Logger LOGGER = LoggerFactory.getLogger(JenkinsItemSynchronizer.class);

    public JenkinsItemSynchronizer(JenkinsServer jenkinsServer, JenkinsProperties properties,
                                   JenkinsSyncProperties syncProperties) {
        this.jenkinsServer = jenkinsServer;
        this.syncProperties = syncProperties;
        templateEngine = TemplateUtil.createEngine(new TemplateConfig(properties.getTemplatePath(),
                TemplateConfig.ResourceMode.CLASSPATH));
    }

    @Override
    public void run(ApplicationArguments args) throws IOException {
        if (syncProperties.getItems() == null) {
            return;
        }
        Set<String> itemNames = syncProperties.getItems()
                .stream()
                .map(JenkinsSyncProperties.Item::getName)
                .collect(Collectors.toSet());
        Set<String> existsItemNames = jenkinsServer.getJobs().keySet();
        for (String itemName : existsItemNames) {
            if (!itemNames.contains(itemName)) {
                jenkinsServer.deleteJob(itemName);
                LOGGER.info("Item removed successfully: {}", itemName);
            }
        }
        Map<String, Template> templateMap = syncProperties.getItems()
                .stream()
                .map(JenkinsSyncProperties.Item::getTemplateResource)
                .distinct()
                .collect(Collectors.toMap(Function.identity(), s -> templateEngine.getTemplate(s + ".ftl")));
        for (JenkinsSyncProperties.Item item : syncProperties.getItems()) {
            StringWriter writer = new StringWriter();
            templateMap.get(item.getTemplateResource())
                    .render(item.getTemplateParams(), writer);
            String itemName = item.getName();
            try {
                String jobXml = writer.toString();
                if (!existsItemNames.contains(itemName)) {
                    jenkinsServer.createJob(itemName, jobXml);
                    LOGGER.info("Item created successfully: {}", itemName);
                } else if (!Objects.equals(jenkinsServer.getJobXml(itemName), jobXml)) {
                    jenkinsServer.updateJob(itemName, jobXml);
                    LOGGER.info("Item modified successfully: {}", itemName);
                } else {
                    LOGGER.info("Ignore unchanged item: {}", itemName);
                }
            } catch (IOException e) {
                LOGGER.error("Item operation failed: " + itemName, e);
            }
        }
    }
}
